package com.shenmazong.serveruserapi.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.shenmazong.utils.ConstUtils;
import com.shenmazong.utils.ResponseResult;
import com.shenmazong.TbNo;
import com.shenmazong.TbUser;
import com.shenmazong.serveruserapi.mapper.ITbNoMapper;
import com.shenmazong.serveruserapi.mapper.ITbUserMapper;
import com.shenmazong.serveruserapi.service.UserService;
import com.shenmazong.serveruserapi.util.JwtTokenUtils;
import com.shenmazong.serveruserapi.util.SmsUtils;
import com.shenmazong.utils.UploadFileUtils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class UserServiceImpl implements UserService {

    @Autowired
    private ITbUserMapper iTbUserMapper;

    @Autowired
    private ITbNoMapper iTbNoMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    Environment environment;

    @Override
    public ResponseResult getUserById(Integer userId) {
        ResponseResult result = ResponseResult.SUCCESS();
        HashMap<String, Object> dataMap = new HashMap<>();

        String port = environment.getProperty("local.server.port");
        dataMap.put("port", port);
        dataMap.put("userId", userId);

        result.setResult(dataMap);

        return result;
    }

    /**
     * TODO 发送短信（新用户的注册）
     * @param mobile
     * @return
     */
    @Override
    public ResponseResult sendSms(String mobile) {
        ResponseResult result = ResponseResult.SUCCESS();

        //--1 发送验证码
        Integer icode = (int)((Math.random()*9+1)*100000);
        Integer ret = SmsUtils.sendAliyunSms(mobile, String.valueOf(icode));
        if(!ret.equals(0)) {
            result.setCode(-1);
            result.setMessage("短信发送失败");
            return result;
        }

        //--2 保存手机号
        TbUser user = iTbUserMapper.selectOne(
                new QueryWrapper<TbUser>()
                        .eq("mobile", mobile)
                        .last("limit 1")
        );
        if(user == null) {
            TbUser newUser = new TbUser();
            newUser.setMobile(mobile);
            newUser.setNickname("星星用户" + String.valueOf(icode));
            newUser.setHeadurl(ConstUtils.DEFAUT_USER_HEAD_URL);

            // 获取userno
            Integer no = (Integer) redisTemplate.opsForSet().pop(ConstUtils.QUEUE_USER_NO_NAME);
            if(no == null) {
                result.setCode(-1);
                result.setMessage("获取用户编码失败");
                return result;
            }

            newUser.setUserno(no);
            iTbUserMapper.insert(newUser);

            //-- 设置用户编码被使用
            TbNo tbNo = iTbNoMapper.selectOne(
                    new QueryWrapper<TbNo>()
                            .eq("userno", no)
                            .last("limit 1"));
            if(tbNo == null) {
                result.setCode(-1);
                result.setMessage("更新户编码状态失败");
                return result;
            }
            tbNo.setStatus(1);
            iTbNoMapper.updateById(tbNo);
        }

        //--3 保存验证码（redis，过期时间5分钟）
        String key = "code_" + mobile;
        redisTemplate.opsForValue().set(key, icode, 60*5, TimeUnit.SECONDS);

        return result;
    }

    /**
     * TODO 校验验证码（登录）
     * @param mobile
     * @param vcode
     * @return
     */
    @Override
    public ResponseResult verifyCode(String mobile, Integer vcode) {
        ResponseResult result = ResponseResult.SUCCESS();
        HashMap<String, Object> dataMap = new HashMap<>();

        //--1 验证验证码
        String key = "code_" + mobile;
        Integer code = (Integer) redisTemplate.opsForValue().get(key);
        if(code == null) {
            result.setCode(-1);
            result.setMessage("获取用户验证码失败");
            return result;
        }
        if(!code.equals(vcode)) {
            result.setCode(-1);
            result.setMessage("用户验证码不一致");
            return result;
        }

        //--2 获取用户信息
        TbUser user = iTbUserMapper.selectOne(
                new QueryWrapper<TbUser>()
                        .eq("mobile", mobile)
                        .last("limit 1")
        );
        if(user == null) {
            result.setCode(-1);
            result.setMessage("获取用户信息失败");
            return result;
        }

        //--3 生成token（JWT）
        String token = JwtTokenUtils.makeToken(user.getId(), user.getNickname());
        dataMap.put("token", token);
        dataMap.put("user", user);

        result.setResult(dataMap);

        return result;
    }

    /**
     * TODO 实现快捷登录，无需手机号，只需要以前的Token
     * @param userId
     * @param userToken
     * @return
     */
    @Override
    public ResponseResult quickLogin(Integer userId, String userToken) {
        ResponseResult result = ResponseResult.SUCCESS();
        HashMap<String, Object> dataMap = new HashMap<>();

        //--1 检查用户ID
        TbUser user = iTbUserMapper.selectById(userId);
        if(user == null) {
            result.setCode(-1);
            result.setMessage("获取用户信息失败");
            return result;
        }

        //--2 检验token，从token中获取userid
        if(StringUtils.isNotBlank(userToken)) {
            log.info("userToken=" + userToken);
        }
        else {
            result.setCode(-1);
            result.setMessage("无效的token数据");
            return result;
        }

        Integer uid = 0;
        String nickName = null;
        Claims claims = null;
        try {
            claims = Jwts.parser()
                    .setSigningKey(ConstUtils.TOKEN_PASS_WORD)
                    .parseClaimsJws(userToken)
                    .getBody();

            uid = Integer.valueOf(claims.getId());
            nickName = claims.getSubject();
        }
        catch (ExpiredJwtException e) {
            claims = e.getClaims();
            uid = Integer.valueOf(claims.getId());
            nickName = claims.getSubject();
            System.out.println("token expired");
        } catch (SignatureException e) {
            System.out.println("token signature error");
        } catch (Exception e) {
            System.out.println("token error");
        }
        if(uid.equals(0)) {
            result.setCode(-1);
            result.setMessage("解析token数据错误");
            return result;
        }
        else if(!uid.equals(userId)) {
            result.setCode(-1);
            result.setMessage("userId错误");
            return result;
        }

        //--3 发布最新的token
        String token = JwtTokenUtils.makeToken(user.getId(), user.getNickname());
        dataMap.put("token", token);
        dataMap.put("user", user);

        result.setResult(dataMap);

        return result;
    }

    /**
     * TODO 实现用户头像的上传
     * @param userId
     * @param file
     * @return
     */
    @Override
    public ResponseResult uploadHead(Integer userId, MultipartFile file) {
        ResponseResult result = ResponseResult.SUCCESS();

        //--1 验证用户是否存在
        TbUser user = iTbUserMapper.selectById(userId);
        if(user == null) {
            result.setCode(-1);
            result.setMessage("获取用户信息失败");
            return result;
        }

        //--2 上传文件
        if(file.isEmpty()){
            log.info("上传文件为空");
            result.setCode(-1);
            result.setMessage("上传文件为空");
            return result;
        }
        String fileName = file.getOriginalFilename();
        int size = (int) file.getSize();
        log.info(fileName + "-->" + size);

        UUID uuid = UUID.randomUUID();
        String suffix = fileName.substring(fileName.lastIndexOf(".")).toLowerCase();
        String newName = uuid.toString() + suffix;
        String headUrl = UploadFileUtils.uploadAliyunOss(file, newName);
        if(headUrl == null) {
            result.setCode(-1);
            result.setMessage("上传文件到OSS失败");
            return result;
        }

        //--3 修改用户头像链接
        user.setHeadurl(headUrl);
        iTbUserMapper.updateById(user);

        return result;
    }

    /**
     * TODO 修改用户信息
     * @param userId
     * @param nickName
     * @param sex
     * @return
     */
    @Override
    public ResponseResult setUserInfo(Integer userId, String nickName, Integer sex) {
        ResponseResult result = ResponseResult.SUCCESS();
        HashMap<String, Object> dataMap = new HashMap<>();

        //--1 获取用户信息
        TbUser user = iTbUserMapper.selectById(userId);
        if(user == null) {
            result.setCode(-1);
            result.setMessage("获取用户信息失败");
            return result;
        }

        //--2 修改用户新
        user.setNickname(nickName);
        user.setSex(sex);
        iTbUserMapper.updateById(user);

        dataMap.put("user", dataMap);
        result.setResult(dataMap);

        return result;
    }

    /**
     * TODO 设置用户的状态（锁定/解锁）
     * @param userId
     * @param status
     * @return
     */
    @Override
    public ResponseResult setUserStatus(Integer userId, Integer status) {
        ResponseResult result = ResponseResult.SUCCESS();
        HashMap<String, Object> dataMap = new HashMap<>();

        //--1 获取用户信息
        TbUser user = iTbUserMapper.selectById(userId);
        if(user == null) {
            result.setCode(-1);
            result.setMessage("获取用户信息失败");
            return result;
        }

        //--2 修改用户新
        user.setStatus(status);
        iTbUserMapper.updateById(user);

        dataMap.put("user", dataMap);
        result.setResult(dataMap);

        return result;
    }
}
